package com.egg.basic.service.quartz;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.egg.basic.entity.quartz.Quartz;
import com.egg.basic.mapper.quartz.QuartzMapper;
import com.egg.basic.model.request.QuartzPauseOrResumePatch;
import com.egg.basic.model.request.QuartzPostOrPut;
import com.egg.common.core.exception.CustomException;
import com.egg.common.mybatis.service.impl.BaseServiceImpl;
import com.egg.common.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.CronExpression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * <p>
 * 定时任务表 服务实现类
 * </p>
 *
 * @author east
 * @since 2021-12-02
 */
@Slf4j
@Service
public class QuartzServiceImpl extends BaseServiceImpl<QuartzMapper, Quartz> {


    @Autowired(required = false)
    private QuartzManage quartzManage;

    /**
     * 存在判断
     *
     * @param jobName
     * @return
     */
    private boolean existByJobName(String jobName) {
        return existByJobName(jobName, Optional.empty());
    }

    /**
     * 存在判断
     *
     * @param jobName
     * @param filterId
     * @return
     */
    private boolean existByJobName(String jobName, Optional<Serializable> filterId) {
        if (ObjectUtil.isEmpty(jobName)) {
            return true;
        }
        LambdaQueryWrapper<Quartz> qw = buildLambdaSortQw();
        qw.eq(Quartz::getJobName, jobName);
        filterId.ifPresent(o -> qw.notIn(Quartz::getId, o));
        return count(qw) > 0;
    }

    /**
     * 存在判断
     *
     * @param beanName
     * @param methodName
     * @return
     */
    private boolean existByBeanAndMethod(String beanName, String methodName) {
        return existByBeanAndMethod(beanName, methodName, Optional.empty());
    }

    /**
     * 存在判断
     *
     * @param beanName
     * @param methodName
     * @param filterId
     * @return
     */
    private boolean existByBeanAndMethod(String beanName, String methodName, Optional<Serializable> filterId) {
        if (ObjectUtil.isEmpty(beanName) || ObjectUtil.isEmpty(methodName)) {
            return true;
        }
        LambdaQueryWrapper<Quartz> qw = buildLambdaSortQw();
        qw.eq(Quartz::getBeanName, beanName)
                .eq(Quartz::getMethodName, methodName);
        filterId.ifPresent(o -> qw.notIn(Quartz::getId, o));
        return count(qw) > 0;
    }

    /**
     * 定时任务新增
     *
     * @param save
     * @return
     */
    public Long addQuartz(QuartzPostOrPut save) {
        if (!CronExpression.isValidExpression(save.getCronExpression())) {
            throw new CustomException("cron表达式格式错误");
        }
        boolean exist = existByJobName(save.getJobName());
        if (exist) {
            throw new CustomException("定时器名称重复");
        }
        exist = existByBeanAndMethod(save.getBeanName(), save.getMethodName());
        if (exist) {
            throw new CustomException("定时器工作内容已存在");
        }
        Quartz quartz = JsonUtil.objToObj(save, Quartz.class);
        baseSave(quartz);
        if (null != quartzManage) {
            quartzManage.add(quartz);
        }
        return quartz.getId();
    }

    /**
     * 查询非暂停定时器
     *
     * @return
     */
    public List<Quartz> findNonPause() {
        LambdaQueryWrapper<Quartz> qw = buildLambdaQw();
        qw.eq(Quartz::getPause, false);
        return list(qw);
    }

    /**
     * 暂停任务
     *
     * @param id
     */
    public void pauseById(Serializable id) {
        QuartzPauseOrResumePatch put = new QuartzPauseOrResumePatch();
        put.setPause(true);
        pauseOrResumeQuartz(id, put);
    }

    /**
     * 修改
     *
     * @param id
     * @param save
     */
    @Transactional(rollbackFor = Throwable.class)
    public Long putQuartz(Serializable id, QuartzPostOrPut save) {
        if (!CronExpression.isValidExpression(save.getCronExpression())) {
            throw new CustomException("cron表达式格式错误");
        }
        Quartz exist = baseGetById(id);
        boolean repeatName = existByJobName(save.getJobName(), Optional.of(id));
        if (repeatName) {
            throw new CustomException("定时器名称重复");
        }
        repeatName = existByBeanAndMethod(save.getBeanName(), save.getMethodName(), Optional.of(id));
        if (repeatName) {
            throw new CustomException("定时器工作内容已存在");
        }
        Quartz quartz = JsonUtil.objToObj(save, Quartz.class);
        quartz.setId(exist.getId());
        baseSave(quartz);
        if (null != quartzManage) {
            quartzManage.delete(exist);
            quartzManage.add(quartz);
        }
        return exist.getId();
    }

    /**
     * 暂停或启用
     *
     * @param id
     * @param pause
     * @return
     */
    @Transactional(rollbackFor = Throwable.class)
    public Long pauseOrResumeQuartz(Serializable id, QuartzPauseOrResumePatch pause) {
        Quartz quartz = baseGetById(id);
        if (Objects.equals(quartz.getPause(), pause.getPause())) {
            return quartz.getId();
        }
        quartz.setPause(pause.getPause());
        baseSave(quartz);
        if (null != quartzManage) {
            if (quartz.getPause()) {
                //暂停
                quartzManage.pause(quartz);
            } else {
                //恢复
                quartzManage.resume(quartz);
            }
        }
        return quartz.getId();
    }

    /**
     * 删除
     *
     * @param ids
     */
    public void delQuartz(Collection<? extends Serializable> ids) {
        List<Quartz> list = baseFindById(ids);
        list.forEach(o -> {
            this.baseDel(o.getId());
            if (null != quartzManage) {
                quartzManage.delete(o);
            }
        });
    }

    /**
     * 立即运行
     *
     * @param id
     */
    public void runQuartz(Serializable id) {
        Quartz quartz = baseGetById(id);
        if (null != quartzManage) {
            quartzManage.run(quartz);
        }
    }

    /**
     * 分页
     *
     * @param current
     * @param pageSize
     * @param jobName
     * @param pause
     * @return
     */
    public Page<Quartz> page(
            Integer current, Integer pageSize
            , Optional<String> jobName
            , Optional<Boolean> pause
    ) {
        LambdaQueryWrapper<Quartz> qw = buildLambdaSortQw();
        jobName.ifPresent(o -> qw.like(Quartz::getJobName, o));
        pause.ifPresent(o -> qw.eq(Quartz::getPause, o));
        return page(new Page<>(current, pageSize), qw);
    }


}
